package com.maxmlr.nacosserver.config;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author max
 * @version 1.0
 * @Package com.maxmlr.nacosserver.config
 * @ClassName WebLogAspect
 * @Description 日志切面
 * @Copyright Copyright (c) 2018: www.maxmlr.com.
 * @since 2018年12月15日 下午6:12:49
 */
@Aspect
@Component
public class WebLogAspect {
    Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    @Pointcut("execution (* com.maxmlr.nacosserver.controller..*.* (..))")
    private void anyMethod() {
    } // 声明一个切入点，anyMethod为切入点名称

    /**
     * @param joinPoint
     * @Title doAccessCheck
     * @Description 声明该方法是一个前置通知：在目标方法开始之前执行
     * @author max
     * @since 2018年12月15日 下午6:13:27
     */
    //@Before("anyMethod()")
    public void doAccessCheck(JoinPoint joinPoint) {
        // 接收到请求，记录请求内容
        HttpServletRequest request = getHttpServletRequest();
        Class declaringType = joinPoint.getTarget().getClass();// 类名
        Logger logger = LoggerFactory.getLogger(declaringType);// 类名

        // 记录下请求内容
        logger.info("请求URL : " + request.getRequestURL().toString());
        logger.info("请求HTTP_METHOD : " + request.getMethod());
        logger.info("请求IP : " + request.getRemoteAddr());
        logger.info("请求CLASS_METHOD : " + declaringType.getName() + "." + joinPoint.getSignature().getName());
        logger.info("请求参数ARGS : " + JSON.toJSONString(joinPoint.getArgs()));

    }


    /**
     * @param joinPoint
     * @param ret
     * @Title doAfterReturning
     * @Description 后置通知
     * @author max
     * @since 2018年12月15日 下午6:13:41
     */
    //@AfterReturning(returning = "ret", value = "anyMethod()")
    public void doAfterReturning(JoinPoint joinPoint, Object ret) {
        Class declaringType = joinPoint.getTarget().getClass();// 类名
        Logger logger = LoggerFactory.getLogger(declaringType);// 类名
        // 处理完请求，返回内容
        logger.info("请求响应信息RESPONSE : " + JSON.toJSONString(ret));

    }

    // @After("anyMethod()")
    public void doAfter() {
        System.out.println("最终通知");
    }

    /**
     * @param pjp
     * @return
     * @throws Throwable
     * @Title doAround
     * @Description 环绕通知
     * @author max
     * @since 2018年12月15日 下午6:13:09
     */
    @Around("anyMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request = getHttpServletRequest();
        Class declaringType = pjp.getTarget().getClass();// 类名
        Logger logger = LoggerFactory.getLogger(declaringType);// 类名

        // 记录下请求内容
        logger.info("请求URL : " + request.getRequestURL().toString());
        logger.info("请求HTTP_METHOD : " + request.getMethod());
        logger.info("请求IP : " + request.getRemoteAddr());
        logger.info("请求CLASS_METHOD : " + declaringType.getName() + "." + pjp.getSignature().getName());
        logger.info("请求参数ARGS : " + JSON.toJSONString(pjp.getArgs()));
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 开始
        Object retVal = null;
        try {
            retVal = pjp.proceed();
        } catch (Exception e) {
            logger.error("请求响应发现未知异常:", e);
        }
        stopWatch.stop();
        // 结束
        logger.info("请求响应耗时: {} ms", stopWatch.getTotalTimeMillis());
        logger.info("请求响应信息RESPONSE : " + JSON.toJSONString(retVal));
        return retVal;
    }

    /**
     * @param joinPoint
     * @param ex
     * @Title doAfterThrowing
     * @Description 发现未知异常通知
     * @author max
     * @since 2018年12月15日 下午6:14:29
     */
    //@AfterThrowing(value = "anyMethod()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        Class declaringType = joinPoint.getTarget().getClass();// 类名
        Logger logger = LoggerFactory.getLogger(declaringType);// 类名
        logger.error("通知中发现未知异常:", ex);
    }


    public static HttpServletRequest getHttpServletRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request;
    }

}
